package com.mofeng.myshop.until.component;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.*;
import java.net.MalformedURLException;
import java.net.SocketException;

/**
 * ftp工具类
 * 2021年10月20日21:30:28
 */
@Slf4j
@Component
public class FtpUtil {
    @Value("${ftp.host}")
    private String hostname;  //ftp服务器ip
    @Value("${ftp.port}")
    private int port;    //ftp服务器端口
    @Value("${ftp.name}")
    private String username;//用户名
    @Value("${ftp.password}")
    private String password;//密码

    /**
     * 初始化ftp服务器
     */
    public FTPClient getFtpClient() {
        FTPClient ftpClient = new FTPClient();
        ftpClient.setControlEncoding("UTF-8");
        try {
            ftpClient.setDataTimeout(1000 * 120);//设置连接超时时间
            ftpClient.connect(hostname, port); // 连接ftp服务器
            ftpClient.login(username, password); // 登录ftp服务器
            int replyCode = ftpClient.getReplyCode(); // 是否成功登录服务器
            if (!FTPReply.isPositiveCompletion(replyCode)) {
                log.error("connect failed...ftp server:" + hostname + ":" + port);
            }
        } catch (MalformedURLException e) {
            log.error(e.getMessage(), e);
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        }
        return ftpClient;
    }

    /**
     * 上传文件
     *
     * @param targetDir   ftp服务保存地址
     * @param fileName    上传到ftp的文件名
     * @param inputStream 输入文件流
     * @return
     */
    public boolean upload(String targetDir, String fileName, InputStream inputStream) {
        boolean isSuccess = false;
        FTPClient ftpClient = getFtpClient();
        try {
            if (ftpClient.isConnected()) {
                ftpClient.setFileType(FTP.BINARY_FILE_TYPE);//设置上传文件类型为二进制，否则将无法打开文件
                // 设置为被动模式(如上传文件夹成功，不能上传文件，注释这行，否则报错refused:connect  )
                ftpClient.enterLocalPassiveMode();//设置被动模式，文件传输端口设置
                if (!ftpClient.changeWorkingDirectory(targetDir)) {
                    String[] filePaths = targetDir.split("/");
                    for (String filePath : filePaths) {
                        ftpClient.makeDirectory(filePath);
                        ftpClient.changeWorkingDirectory(filePath);
                    }
                }
                if (ftpClient.storeFile(fileName, inputStream)) {
                    isSuccess = true;
                }
                inputStream.close();
                ftpClient.logout();
            } else {
                log.error("FTP连接建立失败");
            }
        } catch (IOException e) {
            log.error(fileName + "文件上传到FTP出现异常");
            log.error(e.getMessage(), e);
        } finally {
            closeFtpClient(ftpClient);
            closeStream(inputStream);
        }
        return isSuccess;
    }

    /*下载文件*/
    public InputStream download(FTPClient ftpClient, String filePath, String name) throws IOException {
        InputStream inputStream = null;
        try {
            ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
            ftpClient.enterLocalPassiveMode();//设置被动模式，文件传输端口设置
            filePath = new String(filePath.getBytes("utf-8"), "iso-8859-1");
            name = new String(name.getBytes("utf-8"), "iso-8859-1");
            boolean b = ftpClient.changeWorkingDirectory(filePath);
            inputStream = ftpClient.retrieveFileStream(name);
        } catch (FileNotFoundException e) {
            printError(e,"没有找到文件");
        } catch (SocketException e) {
            printError(e,"FTP连接失败.");
        } catch (IOException e) {
            printError(e,"文件读取错误。");
        } finally {
            if (ftpClient != null) {
                FtpUtil.closeFtpClient(ftpClient);
            }
        }
        return inputStream;
    }

    /**
     * 删除文件 *
     *
     * @param pathname FTP服务器保存目录 *
     * @param filename 要删除的文件名称 *
     * @return
     */
    public boolean deleteFile(String pathname, String filename) {
        boolean flag = false;
        FTPClient ftpClient = getFtpClient();
        try {
            log.info("开始删除文件");
            if (ftpClient.isConnected()) {
                //切换FTP目录
                ftpClient.changeWorkingDirectory(pathname);
                ftpClient.enterLocalPassiveMode();
                ftpClient.dele(filename);
                ftpClient.logout();
                flag = true;
                log.info("删除文件成功");
            } else {
                log.info("删除文件失败");
            }
        } catch (Exception e) {
            log.error("删除文件失败");
            log.error(e.getMessage(), e);
        } finally {
            if (ftpClient.isConnected()) {
                try {
                    ftpClient.disconnect();
                } catch (IOException e) {
                    log.error(e.getMessage(), e);
                }
            }
        }
        return flag;
    }

    public static void closeFtpClient(FTPClient ftpClient) {
        if (ftpClient.isConnected()) {
            try {
                ftpClient.disconnect();
            } catch (IOException e) {
                log.error(e.getMessage(), e);
            }
        }
    }

    private static void closeStream(Closeable closeable) {
        if (null != closeable) {
            try {
                closeable.close();
            } catch (IOException e) {
                log.error(e.getMessage(), e);
            }
        }
    }

    //改变目录路径
    private boolean changeWorkingDirectory(FTPClient ftpClient, String directory) {
        boolean flag = true;
        try {
            flag = ftpClient.changeWorkingDirectory(directory);
            if (flag) {
                log.info("进入文件夹" + directory + " 成功！");

            } else {
                log.info("进入文件夹" + directory + " 失败！开始创建文件夹");
            }
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        }
        return flag;
    }

    //创建多层目录文件，如果有ftp服务器已存在该文件，则不创建，如果无，则创建
    private boolean CreateDirectory(FTPClient ftpClient, String remote) throws IOException {
        boolean success = true;
        String directory = remote;
        if (!remote.endsWith(File.separator)) {
            directory = directory + File.separator;
        }
        // 如果远程目录不存在，则递归创建远程服务器目录
        if (!directory.equalsIgnoreCase(File.separator) && !changeWorkingDirectory(ftpClient, new String(directory))) {
            int start = 0;
            int end = 0;
            if (directory.startsWith(File.separator)) {
                start = 1;
            } else {
                start = 0;
            }
            end = directory.indexOf(File.separator, start);
            String path = "";
            String paths = "";
            while (true) {
                String subDirectory = new String(remote.substring(start, end).getBytes("GBK"), "iso-8859-1");
                path = path + File.separator + subDirectory;
                if (!existFile(ftpClient, path)) {
                    if (makeDirectory(ftpClient, subDirectory)) {
                        changeWorkingDirectory(ftpClient, subDirectory);
                    } else {
                        log.error("创建目录[" + subDirectory + "]失败");
                        changeWorkingDirectory(ftpClient, subDirectory);
                    }
                } else {
                    changeWorkingDirectory(ftpClient, subDirectory);
                }

                paths = paths + File.separator + subDirectory;
                start = end + 1;
                end = directory.indexOf(File.separator, start);
                // 检查所有目录是否创建完毕
                if (end <= start) {
                    break;
                }
            }
        }
        return success;
    }

    //判断ftp服务器文件是否存在
    private boolean existFile(FTPClient ftpClient, String path) throws IOException {
        boolean flag = false;
        FTPFile[] ftpFileArr = ftpClient.listFiles(path);
        if (ftpFileArr.length > 0) {
            flag = true;
        }
        return flag;
    }

    //创建目录
    private boolean makeDirectory(FTPClient ftpClient, String dir) {
        boolean flag = true;
        try {
            flag = ftpClient.makeDirectory(dir);
            if (flag) {
                log.info("创建文件夹" + dir + " 成功！");

            } else {
                log.info("创建文件夹" + dir + " 失败！");
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return flag;
    }

    private void printError(Exception e, String eTitle) {
        log.error(eTitle + "：{}, 异常类型：{},详细信息：", e.getMessage(), e.getClass(), e);
    }
}